import axios, {
  AxiosRequestConfig, AxiosError, AxiosResponse, Canceler,
} from 'axios';
import { Modal, Notification } from '@douyinfe/semi-ui';
import { getToken } from '@/utils/storage';
import { RQ_ContentTypeEnum, RQ_ExceptionEnum } from '@/types/httpEnum';

// API Response Model
export interface ResponseData<T> {
  code: number; // 成功表示 1 成功 0 失败
  data: T; // 返回的信息体，接口定义时传入对应泛型
  msg: string; // 附加信息，失败时可传入原因
}

// 自定义请求配置
interface MyAxiosRequestConfig extends AxiosRequestConfig {
  isOthers?: boolean // 是否第三方 API, 为 true 则不自动添加 baseURL 信息
}

// 泛型接口
export interface Service {
  <T>(config:MyAxiosRequestConfig): Promise<ResponseData<T>>
}

// 创建 axios 实例
const Iservice = axios.create({
  baseURL: process.env.BASE_API_URL, // api base_url
  timeout: 60000, // 请求超时时间 调用登录接口时间太久测试此超时时间位测试超时时间
  withCredentials: true, // 如需要携带cookie 该值需设为true
});

// 如果请求失败了，则后续请求进行取消
let pendingList:PendingType[] = [];

// 定义接口
interface PendingType {
  url?: string;
  cancel: Canceler;
}

// 移除重复请求
const removePending = (config: MyAxiosRequestConfig) => {
  for (const key in pendingList) {
    const item: number = +key;
    const pending: PendingType = pendingList[key];
    // 当前请求在数组中存在时执行函数体
    if (pending.url === config.url) {
      // 执行取消操作
      pending.cancel('操作太频繁，请稍后再试');
      // 从数组中移除记录
      pendingList.splice(item, 1);
    }
  }
};

// 失败的handle
const handleError = (error:AxiosError) => {
  if (error.response) {
    if (error.response.status === RQ_ExceptionEnum.REQUEST_ERROR) {
      Notification.error({
        title: '提示',
        content: '系统异常，请稍后重试',
      });
      return;
    }
    if (error.response.status === RQ_ExceptionEnum.REQUEST_NOT_FOUND) {
      Notification.error({
        title: '提示',
        content: '请求地址不正确，404 Not Found!',
      });
      return;
    }
    if (error.response.status === RQ_ExceptionEnum.REQUEST_AUTH) {
      Modal.confirm({
        title: '确定登出?',
        content: '由于长时间未操作，您已被登出，可以取消继续留在该页面，或者重新登录',
        okText: '重新登录',
        onOk() {
          console.log('need logout');
        },
      });
    }
    // 取消请求
    pendingList.forEach((pending) => {
      pending.cancel('Canceled');
    });
    pendingList = [];
  }
  return Promise.reject(error);
};

// 请求拦截
Iservice.interceptors.request.use((config: MyAxiosRequestConfig) => {
  // 删除重复请求
  removePending(config);
  // 设置cancelToken对象
  config.cancelToken = new axios.CancelToken((c) => {
    pendingList.push({ url: config.url, cancel: c });
  });
  // 设置其他的请求地址，不添加 baseURL
  if (config.isOthers) {
    config.baseURL = undefined;
  }
  // 判断 header 存在并设置对应值
  if (config.headers) {
    // 添加 Token
    const token = getToken();
    if (token) {
      config.headers.Authrization = token;
    }
    // 设置请求 Content-Type
    if (!config.headers['Content-Type']) {
      config.headers['Content-Type'] = RQ_ContentTypeEnum.JSON;
    }
    // TODO 设置页面多语言
  }

  return config;
}, handleError);

// 请求结果拦截
Iservice.interceptors.response.use((response: AxiosResponse) => {
  const requestResponseType = response.config.responseType;
  if (requestResponseType) { // 判断是文件下载类型
    if (response.status === 200) {
      return Promise.resolve(response);
    }
    Notification.error({
      title: '提示',
      content: '系统处理出现错误，下载失败',
    });
    return Promise.reject(new Error(response.data.msg));
  }
  // 2xx 范围内的状态码都会触发该函数, 我们直接返回
  return Promise.resolve(response);
}, handleError);

// 封装为 Service
const service: Service = async (config) => {
  const response = await Iservice(config);
  return response.data;
};

export default service;
